[初学者向け]PythonとTypeScriptを使ってLambdaで始めるaws-cdk
はじめに
cdkを使い始めて、AWSのリソース設定が柔軟に行える魅力を実感し始めました。ですが、複数の言語を利用する場合、動作に問題のないディレクトリ構成が必要となります。
今回はTypeScriptとPythonにて、試行錯誤した結果を備忘録含めて書き出してみました。
ファイル・ディレクトリ構成
作業用ディレクトリルートのappにはビルド用のスクリプト等を置いています。
- app ├ Pipfile ├ deploy.sh ├ cdk/ # cdk用ファイル一式 └ lambda_function/ # python実装
初期設定
mkdir app/ cd app/ export PIPENV_VENV_IN_PROJECT=1 pipenv --python 3.8 mkdir lambda_function/ mkdir cdk/ cd cdk/ cdk init app --language typescript cdk bootstrap
pipenvを作業ディレクトリルートで行っていますが、これはPythonでのLambda関数実装ディレクトリとLayer用モジュールのインストールディレクトリの分離を優先したためです。
分離させてLambda関数実装ディレクトリのサイズを抑えることで、管理コンソール上からの確認が行いやすくなります。
Layer用ディレクトリはデプロイ時にのみ作成しているため、ここでは触れません。
サービス関係の実装
詳細なLambda実装を除いて、cdkで収めてしまいました。
npm install @aws-cdk/aws-lambda @aws-cdk/aws-iam
cdk/lib/cdk-stack.ts
import cdk = require( '@aws-cdk/core' ); import lambda = require('@aws-cdk/aws-lambda'); import iam = require('@aws-cdk/aws-iam'); export class CdkStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const executionLambdaRole = new iam.Role(this, 'secureLambdaRole', { roleName: 'lambdaSecureExecutionRole', assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'), ] }); const pythonModulesLayer = new lambda.LayerVersion(this, 'moduleLayer', { code: lambda.AssetCode.fromAsset('../.lambda_layer'), compatibleRuntimes: [lambda.Runtime.PYTHON_3_8], }); const exampleFunction = new lambda.Function(this, 'exampleFunction', { functionName: 'example-function', runtime: lambda.Runtime.PYTHON_3_8, code: lambda.AssetCode.fromAsset('../lambda_function'), layers: [pythonModulesLayer], handler: 'function.lambda_hundler', timeout: cdk.Duration.seconds(900), role: executionLambdaRole, environment: { TZ: "Asia/Tokyo", } }); } }
忘れずに設定しておきたいのはLambdaのtimeout
指定です。初期設定では3秒となっているため、込み入った動作の場合は完了しないと思われます。
各プロパティ指定について公式ドキュメントと見比べてみてください。
利用モジュールのインストール
pipenv経由でインストールするだけです。Layer用にはデプロイ時に別途操作を行います。
lambda関数の実装
空の実装にも等しいですが、今回は実装前の準備を重点的に行った結果となります。
lambda_function/function.py
def lambda_hundler(event, context): return { 'status': 'ok' }
デプロイ
既にインストールしているモジュールをLayer用ディレクトリに追加します。その後、cdkによるデプロイを行います。
deploy.sh
#!/bin/sh WORKDIR=$(cd $(dirname $0) && pwd) rm -rf ${WORKDIR}/.lambda_layer/ mkdir -p ${WORKDIR}/.lambda_layer/python cd ${WORKDIR}/.lambda_layer pipenv lock -r > requirements.txt pip install -r requirements.txt -t python/ cd ${WORKDIR}/cdk npm run build cdk deploy
% sh deploy.sh WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip. Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue. To avoid this problem you can invoke Python with '-m pip' instead of running pip directly. DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support > [email protected] build /path/to/app/cdk > tsc (node:00000) ExperimentalWarning: The fs.promises API is experimental This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening). Please confirm you intend to make the following modifications: IAM Statement Changes ┌───┬─────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐ │ │ Resource │ Effect │ Action │ Principal │ Condition │ ├───┼─────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤ │ + │ ${secureLambdaRole.Arn} │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │ └───┴─────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘ IAM Policy Changes ┌───┬─────────────────────┬────────────────────────────────────────────────────────────────────────────────┐ │ │ Resource │ Managed Policy ARN │ ├───┼─────────────────────┼────────────────────────────────────────────────────────────────────────────────┤ │ + │ ${secureLambdaRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │ └───┴─────────────────────┴────────────────────────────────────────────────────────────────────────────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Do you wish to deploy these changes (y/n)? y CdkStack: deploying... [0%] start: Publishing XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:current [50%] success: Published XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:current [50%] start: Publishing YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY:current [100%] success: Published YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY:current CdkStack: creating CloudFormation changeset... 0/5 | 22:11:46 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata 0/5 | 22:11:47 | CREATE_IN_PROGRESS | AWS::Lambda::LayerVersion | moduleLayer (moduleLayer00000000) 0/5 | 22:11:47 | CREATE_IN_PROGRESS | AWS::IAM::Role | secureLambdaRole (secureLambdaRole00000000) 0/5 | 22:11:48 | CREATE_IN_PROGRESS | AWS::IAM::Role | secureLambdaRole (secureLambdaRole00000000) Resource creation Initiated 0/5 | 22:11:49 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated 1/5 | 22:11:49 | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata 1/5 | 22:11:53 | CREATE_IN_PROGRESS | AWS::Lambda::LayerVersion | moduleLayer (moduleLayer00000000) Resource creation Initiated 2/5 | 22:11:53 | CREATE_COMPLETE | AWS::Lambda::LayerVersion | moduleLayer (moduleLayer00000000) 3/5 | 22:12:07 | CREATE_COMPLETE | AWS::IAM::Role | secureLambdaRole (secureLambdaRole00000000) ✅ CdkStack
.lambda_layer以下にpythonのパスを追加しているのは、レイヤーに収めるために以下のいずれかのフォルダが必要なためです。
- python
- python/lib/python3.8/site-packages
あとがき
今回cdkを使ってみての大きなメリットは、Layerの追加作業に関して本当に手間が掛からなくなった点でした。
ディレクトリ構成がやや歪に感じていますが、何かしらの設定での対処方法がないか、今後継続して調べてみます。